﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Net;
using IrcBot.Listener;

namespace IrcBot.IrcSender
{
    class BotController
    {
        #region Singleton Members

        private static BotController _controller;

        public static BotController GetInstance()
        {
            if (_controller == null)
            {
                _controller = new BotController();
            }

            return _controller;
        }

        private BotController()
        { }

        public static void DisposeInstance()
        {
            if (_controller != null)
                _controller.Dispose(true);
        }

        public static void KillBot(string name, string channel)
        {
            if (_controller != null)
            {
                
            }
                
        }

        #endregion

        #region Private fields

        private const int DefaultIrcPort = 6667;
        private readonly List<Bot> _activeBots = new List<Bot>();

        #endregion

        #region Public methods

        public void SendMessage(IrcMessage message)
        {
            var bot = GetActiveBotForChannel(message.IrcSafeChannel, message.BotName);
            bot.SendMessage(message.Message);
        }

        public void SendMessage(string channel, string botName, string message)
        {
            var bot = GetActiveBotForChannel(channel, botName);
            bot.SendMessage(message);
        }

        public void Kill(string botName, string channel)
        {
            var bot = FindBot(botName, channel);

            if (bot != null)
            {
                _activeBots.Remove(bot);
                bot.Dispose("Bot being killed by admin.");
            }
        }

        #endregion

        #region Private methods

        private Bot GetActiveBotForChannel(string channel, string botName)
        {
            var bot = FindBot(channel, botName);

            if (bot == null)
            {
                bot = new Bot(botName, channel, GetIrcEndPoint());
                _activeBots.Add(bot);
            }

            return bot;
        }

        private Bot FindBot(string channel, string botName)
        {
            foreach (var existingBot in _activeBots)
            {
                var channelNamesMatch = existingBot.Channel.Equals(channel, StringComparison.InvariantCultureIgnoreCase);
                var botNamesMatch = existingBot.Name.Equals(botName, StringComparison.InvariantCultureIgnoreCase);

                if (channelNamesMatch && botNamesMatch)
                {
                    return existingBot;
                }
            }

            return null;
        }

        private static IPEndPoint GetIrcEndPoint()
        {
            Exception thrownException = null;

            try
            {
                var ip = IPAddress.Parse(ConfigurationManager.AppSettings["IrcServerIp"]);
                var port = ConfigurationManager.AppSettings["IrcServerPort"];

                var portAsInt = (string.IsNullOrEmpty(port)) ? DefaultIrcPort : int.Parse(port);

                if (ip != null)
                {
                    return new IPEndPoint(ip, portAsInt);
                }
            }
            catch (Exception ex)
            {
                thrownException = ex;
            }

            throw new ConfigurationErrorsException(string.Format("The configuration file must contain a valid value for the IrcServerIp setting, which must be a valid IP address. The IrcServerPort setting is optional and will default to {0} if not specified.", DefaultIrcPort), thrownException);
        }

        #endregion

        #region Clean up methods

        public void Dispose()
        {
            Dispose(true);
        }

        private void Dispose(bool suppressFinalise)
        {
            if (_activeBots != null)
            {
                foreach (var bot in _activeBots)
                {
                    bot.Dispose("IrcBot application terminating, killing all bots...");
                }

                _activeBots.Clear();
            }

            if (suppressFinalise)
            {
                GC.SuppressFinalize(this);
            }
        }

        ~BotController()
        {
            Dispose(false);
        }

        #endregion

        public event MessageEventHandler OnBotCreated;
        public event MessageEventHandler OnBotKilled;
        public event MessageEventHandler OnBotError;

    }
}
